KAPITOLA 3
PRÁCE S DATY 1
V předchozích dvou kapitolách jsme získali úvodní přehled o práci v R, respektive RStudiu, a proto se nyní můžeme pustit do vlastní analýzy dat.
Projdeme si základní statistické testy, na něž navážeme příkazy table a summarize. Díky nim se naučíte, kterak lze v krátkém čase získat z dat velice hodnotné informace. Načtěte databázi Katan, jdeme si hrát.
Ačkoliv třetí kapitolu začínáme v Medellínu, které se stalo za dob drogového magnáta Pablo Escobara jedním z nejnebezpečnějších měst v Jižní Americe, není se čeho obávat. Překonejme tedy svůj strach a vrhněme se do útrob této kapitoly.
Popisné statistiky nás budou obdobně jako matematické operace provázet po celou dobu naší práce v R. Pojďme se nyní seznámit s těmi, které jsme na naší cestě prozatím nepotkali. Začněme příkazem summary(). S jeho pomocí zjistíme základní statistické údaje (průměr, medián, minimum, maximum, dolní kvartil a horní kvartil) pro numerické proměnné databáze. Přitom nám tato funkce prozradí i datové typy jednotlivých sloupců včetně jejich délky, která je nicméně u data frame vždy stejná (viz předchozí kapitola).
summary(Katan) Partie Věk Pohlaví Vzdělání
Min. :1.000 Min. :13.00 Length:200 Length:200
1st Qu.:1.000 1st Qu.:20.75 Class :character Class :character
Median :3.000 Median :25.00 Mode :character Mode :character
Mean :3.095 Mean :27.64
3rd Qu.:4.000 3rd Qu.:32.00
Max. :9.000 Max. :75.00
Kolej Práce Kouření Klub
Length:200 Length:200 Length:200 Length:200
Class :character Class :character Class :character Class :character
Mode :character Mode :character Mode :character Mode :character
Děti
Min. :0.00
1st Qu.:0.00
Median :0.00
Mean :0.66
3rd Qu.:1.00
Max. :4.00
Zvídavé studenty jistě tíží otázka, co se stane v případě, použijeme-li příkaz summary() nikoliv pro data frame, ale pro vektor či dílčí proměnnou datové tabulky (např. summary(Katan$Pohlaví))? Na výsledek takového příkazu si ještě chvíli počkejme, jelikož se jím budeme samostatně zabývat v následující lekci.
Dalšími užitečnými příkazy v naší práci s daty bezpochyby budou min(), max(), range() a quantile(). Range v angličtině znamená rozmezí, proto nás v tuto chvíli již asi nepřekvapí, co zajímavého tato funkce dovede. Příkaz quantile() nám kromě minima a maxima zjistí též dolní kvartil (25. percentil dat), medián a horní kvartil (75. percentil dat) numerické proměnné.
min(Katan$Věk) # minimum proměnné Věk v souboru Katan[1] 13
max(Katan$Věk) # maximum proměnné Věk v souboru Katan[1] 75
range(Katan$Věk) # minimum a maximum proměnné Věk v souboru Katan[1] 13 75
quantile(Katan$Věk)
# minimum, dolní kvartil, medián, horní kvartil a maximum proměnné Věk 0% 25% 50% 75% 100%
13.00 20.75 25.00 32.00 75.00
Chceme-li zjistit nejenom kvartily, ale například i kvintily, jež rozdělují soubor dat na pětiny, budeme muset využít v rámci příkazu quantile() jeho parametr probs.
quantile(
Katan$Věk,
probs = c(0, 0.2, 0.4, 0.6, 0.8, 1)) 0% 20% 40% 60% 80% 100%
13 19 23 27 34 75
Osadníci z Katanu jsou hrou pro celou rodinu, o čemž svědčí fakt, že nemladšímu osadníkovi je 13 let a nejstaršímu dokonce 75 let. Jaký je však věkový průměr všech respondentů naší databáze? S příkazem mean() (průměr) jsme se na rozdíl od příkazu median() již setkali. Přesto v jeho zápisu nalezneme něco nového a tím je parametr na.rm = TRUE. Bohužel ne vždy budeme obšťastněni absencí chybějících hodnot v datovém souboru, tak jako v databázi Katan. Aby však funkce mean() mohla správně pracovat i tehdy, máme-li v proměnné prázdné buňky, je nutné příkazu sdělit, že chybějící hodnoty musí přeskočit. V opačném případě by následoval neúprosný error. Parametr na.rm = TRUE využijeme nejenom u průměru či mediánu, ale i u dalších příkazů, na které ještě narazíme. Formát zápisu na.rm = TRUE vychází z té podstaty, že chybějící buňky jsou v R pojmenovány jako NA (Not Available), zatímco rm značí příkaz pro mazání.
mean(Katan$Věk, na.rm = TRUE)[1] 27.64
median(Katan$Věk, na.rm = TRUE)[1] 25
Když už jsme narazili na téma chybějících dat, podívejme se i na příkaz complete.cases(). Ten totiž dokáže vymazat veškeré řádky v data frame, ve kterých nalezne alespoň jednu chybějící hodnotu. Abychom si tento příkaz mohli prakticky vyzkoušet, musíme si nějaké chybějící hodnoty nejdříve vytvořit. K tomu využijeme příkaz edit(), se kterým jsme se seznámili v předchozí kapitole.
DirtyKatan <- edit(Katan)Máme-li už alespoň několik hodnot v Katanu přetvořených na NA (k NA nepřidávejte žádné uvozovky ani apostrofy), můžeme si vyzkoušet následující dvě varianty příkazu complete.cases(). Pomocí první z nich vytvoříme logický vektor TRUE/FALSE a pomocí té druhé získáme data frame s názvem CleanKatan, který bude očištěn od řádků, ve kterých byla nalezena alespoň jedna chybějící hodnota.
CompleteVectorKatan <- complete.cases(DirtyKatan)
# Pomocí tohoto příkazu získáme logický vektor ve tvaru
# TRUE/FALSE, kde TRUE značí řádky bez chybějících údajů.
CleanKatan <- DirtyKatan[complete.cases(DirtyKatan), ]
# Zde získáme databázi CleanKatan obsahující pouze úplné řádky.
# Srovnej předchozí dva příkazy s následujícími příkazy,
# se kterými jsme se poprvé setkali v Panamě.
Katan[ , 1] >= 5
# vs
Katan[Katan[ , 1] >= 5, ]Vraťme se zpět k mean() a podívejme se, kterak lze zjistit průměr nejenom uvnitř proměnné, ale i mezi sloupci. Pro ilustraci si předveďme následující příklad. Vytvořme si datovou tabulku, jež bude obsahovat známky na vysvědčení z chemie, fyziky a biologie nejmenovaného hypotetického studenta z nejmenovaných let jeho dávného studia. Naším úkolem bude spočítat studijní průměry v jednotlivých pololetích za tyto tři přírodovědné předměty, v nichž náš hypotetický student nikdy příliš neexceloval.
# vzorový data frame
známky <- data.frame(
chemie = c(2, 3, 3, 3, 2, 3, 2, 3, 3, 4, 4, 3, 3, 4),
fyzika = c(2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 2),
biologie = c(2, 3, 3, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3))
# výpočet průměru mezi proměnnými
Průměr <- rowMeans(známky[ ,1:3]) [1] 2.000000 2.666667 2.666667 2.333333 2.000000 2.000000 2.000000 2.333333
[9] 2.666667 2.666667 3.000000 2.666667 2.666667 3.000000
Příkaz, se kterým jsme výše uvedený příklad vypočítali, se nazývá rowMeans() (máte-li problém s angličtinou, row znamená řádek a column naopak sloupec). Při jeho zápisu si dávejme pozor na velké M a malé s na jeho konci. Skladba tohoto příkazu je taková, že do kulaté závorky uvádíme výběr sloupců, mezi kterými chceme průměr spočítat. Jelikož chceme počítat průměr po řádcích u proměnných z prvního až třetího sloupce, musíme do závorky nejdříve uvést čárku (nezapomínejte na formát zápisu [řádky, sloupce]) a teprve až poté čísla jedna a tři (do zápisu by místo příkazu 1:3 šlo zapsat též i c(1, 2, 3)).
Stejně jako průměr, lze i součet jednotlivých proměnných provést v obdobném formátu. Pouze místo Means použijeme analogické Sums.
Součet <- rowSums(známky[ ,1:3])
# příkaz vypočítá součet mezi sloupci po řádcích
# pozor na s na konci a velké S oproti sum [1] 6 8 8 7 6 6 6 7 8 8 9 8 8 9
Ne vždy je ale nutné pokoušet se o co nejsofistikovanější styl zápisu, jelikož v jednoduchosti se skrývá síla.
Součet <- známky$chemie + známky$fyzika + známky$biologie [1] 6 8 8 7 6 6 6 7 8 8 9 8 8 9
Znalosti z předchozích kapitol a šesté třídy základní školy by vám měly vystačit i pro výpočet průměru.
Průměr <- (známky$chemie + známky$fyzika + známky$biologie)/3 [1] 2.000000 2.666667 2.666667 2.333333 2.000000 2.000000 2.000000 2.333333
[9] 2.666667 2.666667 3.000000 2.666667 2.666667 3.000000
V rámci statistického zpracování dat se budeme často potýkat nejenom s obyčejným průměrem, ale i rozptylem, směrodatnou odchylkou či korelací. Zatímco však na rozptyl a směrodatnou odchylku, nejste-li statistici, můžete v klidu zapomenout, korelaci byste v této lekci přeskakovat neměli.
var(Katan$Věk) # příkaz vypočítá rozptyl proměnné Věk[1] 126.9049
sd(Katan$Věk) # příkaz vypočítá směrodatnou odchylku proměnné Věk[1] 11.26521
cor(Katan$Věk,
Katan$Partie) # příkaz vypočítá korelaci mezi proměnnými Věk a Partie[1] -0.5375447
Korelace označuje sílu vazby mezi dvěma proměnnými, která je charakterizována číslem od nuly do jedné (plusové znaménko značí pozitivní vazbu, negativní zápornou). Pokud se tedy jedna z proměnných pohybuje jedním či druhým směrem, mění se dle síly vazby i ta druhá a naopak. Dávejte si však pozor na to, že z korelace nelze určit kauzalitu, tj. nepoznáme z ní, kdo koho ve skutečnosti ovlivňuje. Dále není možné zapomenout, že přímá vazba mezi proměnnými může být pouze zdánlivá, jelikož zde může působit třetí zprostředkující proměnná.
Podobně jako u funkce mean(), bohužel i u korelace nás budou často obtěžovat chybějící hodnoty. V takovém případě však nebude možné využít parametr na.rm = TRUE, nýbrž use = "complete.obs". U korelace totiž nepracujeme s jednou, ale dvěma proměnnými.
cor(
Katan$Věk,
Katan$Partie,
use = "complete.obs") [1] -0.5375447
S obyčejnou korelací velmi těsně souvisí i jeho neparametrická varianta, jež se nazývá Spearmanův korelační koeficient. Ten vypočítáme pomocí následujícího příkazu.
cor(
Katan$Věk,
Katan$Partie,
method = "spearman",
use = "complete.obs")[1] -0.7026785
Setkáváte se se Spearmanovým koeficientem poprvé? Spearman nevychází ze samotných hodnot jako běžná korelace, ale z jejich pořadí. Představte si například soutěž v krasobruslení, ve které rozhodují dva rozhodčí, kteří rozdělí dvacet závodnic podle jejich výkonu od nejlepší po nejhorší krasobruslařku. Naším úkolem následně bude zjistit, jak moc byli tito dva rozhodčí ve svém posuzování rozdílní. Nebude nás proto zajímat samotná velikost známky, kterou daná krasobruslařka získala, nýbrž její pořadí mezi ostatními sportovkyněmi. Spearmanův koeficient nicméně stejně jako běžná korelace nabývá hodnot od nuly do jedné (respektive od mínus jedné do jedné, abychom byli naprosto přesní).
Body <- data.frame(
Rozhodčí_Karel = c(1, 5, 3, 2, 12, 15, 4, 7, 8, 11,
9, 13, 20, 19, 6, 10, 14, 16, 17, 18),
Rozhodčí_Jarda = c(1, 4, 3, 5, 11, 15, 2, 8, 13, 12,
9, 7, 20, 19, 14, 10, 6, 18, 16, 17),
Krasobruslařky = c("Barunka", "Karlička", "Zuzanka", "Alžbětka",
"Petruška", "Jája", "Pája", "Pavlínka",
"Věruška", "Helča", "Maruška", "Anička",
"Anežka", "Esterka", "Mariánka", "Verunka",
"Marfuška", "Boženka", "Jiřinka", "Pepička"))
# proměnné Rozhodčí obsahují pořadí krasobruslařek dle rozhodčích
cor(
Body$Rozhodčí_Karel,
Body$Rozhodčí_Jarda,
method = "spearman",
use = "complete.obs")[1] 0.8406015
Spearmanův korelační koeficient činí 0.84, což značí velice silnou závislost (viz následující tabulka). Jarda s Karlem si proto mohou v klidu podat ruce, jelikož jejich hodnocení krasobruslařek není příliš rozdílné.
Absolutní |
hodnota | Interpretace
korelace |
--------------------------------------------
0.01 – 0.09 | triviální nebo žádná korelace
0.10 – 0.29 | nízká korelace
0.30 – 0.49 | střední korelace
0.50 – 0.69 | podstatná korelace
0.70 – 0.89 | velmi silná korelace
0.90 – 1.00 | téměř perfektní korelacePro kontrolu předchozího výpočtu si vypočítejme ještě běžný korelační koeficient. Je-li totiž výše uvedený výsledek správný, měla by hodnota korelačního koeficientu nabývat stejné hodnoty jako u Spearmana. Proč? V příkladu s krasobruslařkami jsme totiž vytvořili data frame, který již obsahoval pořadí závodnic, a nikoliv jejich známky získané od rozhodčích, od nichž by se pořadí teprve odvíjelo.
cor(
Body$Rozhodčí_Karel,
Body$Rozhodčí_Jarda)[1] 0.8406015
Výsledek je stejný, přejděme tedy s klidným srdcem k četnostním tabulkám (table a summary). Před tím se nicméně nezapomeňte podívat na příklady k procvičení. Na závěr ještě zmíním, že statistickým testům bude věnována jedna kompletní lekce v osmé kapitole (Dillí). Máte se věru na co těšit.
Příklad 1
Vypočítejte průměr proměnné Partie z databáze Katan. Uvažujte případ, že máte v databázi chybějící údaje.
Příklad 2
Vypočítejte minimum a maximum proměnné Partie.
Příklad 3
Vypočítejte korelační koeficient mezi proměnnými Věk a Děti.
Příklad 4
Vypočítejte body mass index (hmotnost v kg/výška v m umocněná na druhou) pro následující databázi BMI. Výsledný vektor připojte ke stávající databázi BMI.
BMI <- data.frame(
Hmotnost = c(60, 50, 49, 80, 90, 48,
63, 53, 75, 81),
Výška = c(170, 166, 155, 190, 178,
158, 168, 163, 170, 185))Četnostní tabulky jsou v rámci statistiky zcela nepostradatelnou záležitost. Představte si například, že pracujete s databází, jež obsahuje desetitisíce hodnot o zemědělcích a vy si přejete vědět, kolik jedinců z nich tvoří chovatelé lam (jsme v Peru). Jak na to? Tužka a papír? To jistě ne. Mnohem rychlejší bude využít příkaz summary() nebo table(). My sice desetitisíce hodnot v naší databázi Katan nemáme, přesto nám summary() a table()ušetří spoustu času. Podívejme se nejdříve na formát zápisu u summary(). V něm však nebudeme řešit lamy, ale muže a ženy.
summary(Katan$Pohlaví) muž žena
142 58
Jak je vidět, Osadníci z Katanu přitahují více osadníků nežli osadnic. Některým z Vás ale výše uvedený příkaz fungovat nebude. V případě, že je totiž proměnná Pohlaví datového typu character a nikoliv faktor, uzříte na svém monitoru následující výstup z konzole.
summary(Katan$Pohlaví) Length Class Mode
200 character character
V rámci příkazu table() datový typ proměnné řešit nemusíme. Bude tak pro většinu z nás jistě mnohem přitažlivější.
table(Katan$Pohlaví)
muž žena
142 58
Jaký výstup nás ale bude očekávat v případě chybějících hodnot v databázi? Podívejme se na rozdíl mezi summary() a table().
# Nejdříve si vytvoříme chybějící hodnoty, a teprve až poté
# využijeme summary().
Katan$Pohlaví[1] <- NA
summary(Katan$Pohlaví) muž žena NA's
142 57 1
Katan$Pohlaví[1] <- NA
table(Katan$Pohlaví)
muž žena
142 57
Příkaz summary() nám na rozdíl od table() ukáže nejenom četnost mužů a žen, ale i počet chybějících hodnot. Table() chybějící hodnoty automaticky přeskočí. Ačkoliv je tato skutečnost obecně spíše výhodná, nesmíme na ni zapomenout. Za krátkou chvíli si ukážeme příklad takové situaci, ve které by její opomenutí mohlo způsobit potíže. Prozatím ale pokračujme dál a ukažme si, jak pracuje table() u numerických proměnných.
Chceme-li například zjistit počty hráčů Osadníků podle množství sehraných partií, stačí zapsat následující příkaz. Díky němu poznáme, že necelá polovina respondentů naší databáze odehraje za měsíc maximálně dvě partie této úžasné deskové hry.
table(Katan$Partie)
1 2 3 4 5 6 7 8 9
54 44 39 19 14 10 9 8 3
V případě, že bychom u numerické proměnné použili příkaz summary(), získali bychom přehled o základních statistických údajích, tj. průměru, mediánu či jednotlivých kvantilech proměnné (srovnej s předchozí lekcí a příkazem summary(Katan)).
summary(Katan$Partie) Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 1.000 3.000 3.095 4.000 9.000
Vraťme se však zpět k pohlaví hráčů a hráček Osadníků a pokusme se zjistit jejich jednotlivé podíly v databázi. Kolik procent hráčů tvoří něžné pohlaví? Tak na tuto otázku nám odpoví následující skript.
table(Katan$Pohlaví)/length(Katan$Pohlaví)
muž žena
0.71 0.29
Naše genderově nevyvážená databáze obsahuje bohužel pouze 29 % osadnic. Ženy, kde jste?
Stejný formát zápisu lze samozřejmě použít i pro numerickou proměnnou.
table(Katan$Partie)/length(Katan$Partie)
1 2 3 4 5 6 7 8 9
0.270 0.220 0.195 0.095 0.070 0.050 0.045 0.040 0.015
Na scénu opět přichází hypotetická otázka od zvídavého studenta. Je možné výše uvedený příkaz použít i tehdy, máme-li v databázi chybějící hodnoty? Odpověď je jednoduchá, není. Důvod je prostý. Příkaz table(), jak již víme, nezapočítává chybějící hodnoty. Příkaz length() nicméně tyto hodnoty do délky proměnné započítá. Musíme je tudíž od něj odečíst a to například pomocí příkazu sum() či samotného length(). Ukažme si vše na proměnné Pohlaví.
Katan$Pohlaví[1] <- NA
# nejdříve s využitím příkazu length()
table(Katan$Pohlaví)/length(Katan$Pohlaví[!is.na(Katan$Pohlaví)])
# Pozor: nelze použít následující příkaz!
# length(!is.na(Katan$Pohlaví))
# nyní s pomocí sum()
table(Katan$Pohlaví)/(length(Katan$Pohlaví)-sum(is.na(Katan$Pohlaví)))
# anebo ještě třeba takto, možností je mnoho
table(Katan$Pohlaví)/sum(!is.na(Katan$Pohlaví))
muž žena
0.7135678 0.2864322
V příkazech jste si jistě všimli označení !is.na (respektive is.na), co znamená? Jedná se o funkci, která dokáže detekovat chybějící hodnoty (respektive nechybějící hodnoty). V případě, že námi zkoumaná proměnná chybějící hodnoty obsahuje a naším cílem je zjistit počet těchto hodnot, využijeme tuto funkci a vložíme ji do příkazu lenght() či sum(). S funkcí is.na se v této lekci ještě potkáme, a to v rámci tzv. logických operátorů.
A jaká je vlastně myšlenka příkazu length(Katan$Pohlaví[!is.na(Katan$Pohlaví)])? Příkaz length(Katan$Pohlaví) jistě není třeba blíže vysvětlovat. Ten však nelze použít, jelikož by spočítal počet všech hodnot v proměnné Pohlaví, což není naším cílem, protože v této proměnné existují chybějící hodnoty. Z tohoto důvodu bude naším úkolem vymyslet takový zápis, který pro length() použije pouze hodnoty rozdílné od NA. S výběrem hodnot jsou spojené hranaté závorky. Pokud bychom například chtěli vybrat první hodnotu z proměnné Pohlaví, zapsali bychom do R Katan$Pohlaví[1] (obdobně jako u vektorů). Čísla uvnitř hranatých závorek nám ale pro výběr hodnot rozdílných od NA nepomohou, proto musíme povolat do služby logický vektor, který rozhodne, která z hodnot ve sloupci Pohlaví nabývá NA, a která naopak obsahuje skutečné pozorování. K tomu nám nejlépe poslouží příkaz !is.na(Katan$Pohlaví). Ten následně vložíme do hranatých závorek, z čehož vznikne příkaz Katan$Pohlaví[!is.na(Katan$Pohlaví)].
!is.na(Katan$Pohlaví) [1] FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[13] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[25] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[37] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[49] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[61] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[73] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[85] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[97] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[109] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[121] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[133] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[145] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[157] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[169] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[181] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[193] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Katan$Pohlaví[!is.na(Katan$Pohlaví)] [1] "žena" "muž" "muž" "muž" "muž" "muž" "žena" "žena" "žena" "muž"
[11] "muž" "žena" "žena" "muž" "muž" "muž" "žena" "muž" "muž" "žena"
[21] "muž" "muž" "muž" "žena" "muž" "muž" "muž" "žena" "žena" "muž"
[31] "žena" "žena" "muž" "žena" "žena" "žena" "muž" "muž" "žena" "žena"
[41] "žena" "muž" "žena" "muž" "žena" "muž" "muž" "žena" "žena" "muž"
[51] "muž" "muž" "muž" "muž" "žena" "muž" "muž" "muž" "žena" "žena"
[61] "žena" "muž" "muž" "muž" "muž" "žena" "žena" "muž" "muž" "muž"
[71] "muž" "žena" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž"
[81] "žena" "muž" "muž" "muž" "žena" "muž" "žena" "muž" "žena" "muž"
[91] "muž" "muž" "muž" "žena" "žena" "žena" "žena" "žena" "žena" "muž"
[101] "muž" "žena" "žena" "žena" "muž" "žena" "žena" "žena" "muž" "žena"
[111] "žena" "žena" "muž" "žena" "muž" "žena" "muž" "muž" "muž" "žena"
[121] "muž" "muž" "muž" "muž" "žena" "muž" "muž" "muž" "muž" "muž"
[131] "muž" "muž" "muž" "muž" "muž" "žena" "muž" "muž" "muž" "muž"
[141] "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž"
[151] "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž"
[161] "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "žena"
[171] "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž"
[181] "žena" "muž" "žena" "muž" "muž" "muž" "muž" "muž" "muž" "muž"
[191] "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž" "muž"
Poté už jen stačí tento zápis vložit do length() a výsledkem se stává length(Katan$Pohlaví[!is.na(Katan$Pohlaví)]). Z tohoto důvodu je vám doufám nyní již jasné, proč nelze použít například funkci length(!is.na(Katan$Pohlaví)). S ní si užijete pouze error.
length(Katan$Pohlaví[!is.na(Katan$Pohlaví)])[1] 199
Při tvorbě četnostních tabulek, pracujeme-li s numerickými proměnnými, může být výhodné takovouto proměnnou rozdělit do intervalů, čímž vytvoříme faktor. K tomu nám dobře poslouží příkaz cut(). Představte si například, že chceme rozdělit hráče podle následujících věkových kategorií (teenager do 18 let, dospělý od 18 do 26 let, dospělý od 26 do 65 let, důchodce od 65 let) a následně zjistit procentuální podíly těchto skupin.
AgeGroup <- cut(
Katan$Věk,
breaks = c(0, 18, 26, 65, 150),
right = FALSE,
labels = c("teenager do 18 let", "dospělý od 18 do 26 let",
"dospělý od 26 do 65 let", "důchodce od 65 let"))
# right = FALSE znamená, že v případě c(0, 18, 26, 65, 150)
# intervaly nabývají hodnot <0, 18); <18, 26); atd.
# right = TRUE znamená, že v případě c(0, 18, 26, 65, 150)
# intervaly nabývají hodnot (0, 18>; (18, 26>; atd.
table(AgeGroup)/length(AgeGroup)AgeGroup
teenager do 18 let dospělý od 18 do 26 let dospělý od 26 do 65 let
0.130 0.425 0.425
důchodce od 65 let
0.020
Osadníci z Katanu jsou vysoce populární zejména v nejmladší věkové kategorii. O tom svědčí ta skutečnost, že 55,5 % jedinců z naší databáze je mladší 26 let. Na druhou stranu je možné se setkat i s lidmi v důchodovém věku, kteří Osadníkům též propadli.
V příkazech summary() a table() nezůstanou stranou ani podmínky. Co takhle kupříkladu zjistit, kolik žen nad 25 let naše databáze Katan obsahuje?
summary(
Katan$Pohlaví == "žena" &
Katan$věk > 25)
# příkaz shrne výsledky do podoby TRUE a FALSE Mode FALSE TRUE
logical 190 10
Žen nalezneme v této kategorii pouze deset, na rozdíl od mužů, kterých tu je 79. Srovnáme-li tento výsledek s celkovými počty mužů a žen zvlášť, můžeme usoudit, že ženy po dosažení 26 let ztrácejí o Osadníky zájem. Zatímco muži nad 25 let tvoří přibližně 55 % veškerých mužských hráčů, mezi ženami je to pouhých 17 %.
Podmínky v R tvoříme za pomoci tzv. logických operátorů. Jedním z nich mohou být například dvě rovnítka. Ty použijeme tehdy, chceme-li R sdělit, že z určité proměnné chceme vybrat pouze určité hodnoty, v našem případě pouze ženy. Ampersand, další logický operátor (&), značí to, že se podmínka skládá z více částí, jež musí být současně splněny. Shrnutí logických operátorů můžete vidět v tabulce níže.
Znak | Význam
--------------------------------
< | méně než
<= | méně nebo rovno
> | větší než
>= | větší nebo rovno
== | rovno
!= | nerovno
!x | ne x
x & y | x a y
x | y | x nebo yStejného výsledku jako v předchozím skriptu můžeme opět dosáhnout i s pomocí příkazu table().
table(
Katan$Pohlaví == "žena" &
Katan$Věk > 25)
FALSE TRUE
190 10
Abychom si vyzkoušeli další logické operátory, pokusme se nyní zjistit, kolik mužů v naší databázi pracuje a současně nemá žádné vysokoškolské vzdělání. Bude procento takovýchto jedinců vyšší než u vysokoškoláků?
table(
Katan$Pohlaví == "muž" &
Katan$Práce == "pracuje" &
(Katan$Vzdělání == "ZŠ" | Katan$Vzdělání == "SŠ"))
FALSE TRUE
156 44
table(
Katan$Pohlaví == "muž" &
Katan$Práce == "pracuje" &
(Katan$Vzdělání == "Bc - VŠ" | Katan$Vzdělání == "VŠ"))
FALSE TRUE
159 41
Bude. Dohromady se v naší databázi objevuje 85 pracujících mužů, z nichž necelých 52 % nemá vysokoškolské vzdělání. Osadníci z Katanu se proto u mužů těší stejné oblibě bez ohledu na vzdělání. A jak to vypadá u žen?
table(
Katan$Pohlaví == "žena" &
Katan$Práce == "pracuje" &
(Katan$Vzdělání == "ZŠ" | Katan$Vzdělání == "SŠ"))
FALSE TRUE
196 4
table(
Katan$Pohlaví == "žena" &
Katan$Práce == "pracuje" &
(Katan$Vzdělání == "Bc - VŠ" | Katan$Vzdělání == "VŠ"))
FALSE TRUE
182 18
U těch je situace odlišná. Pracujících žen tu máme celkem 22, z nichž pouze 4 nemají žádné vysokoškolské vzdělání.
Posledním logickým operátorem, který si zde ukážeme, se stane nerovno. S ním už jsme se ale částečně seznámili v rámci příkazu Katan$Pohlaví[!is.na(Katan$Pohlaví)]. Máte ve svém RStudiu stále nahraný soubor DirtyKatan s chybějícími hodnotami z předchozí lekce? Pokud ano, podívejme se na další příkaz. V něm budeme chtít zjistit, kolik máme v databázi žen, které vychovávají alespoň jedno dítě a nechybí jim hodnota v rámci proměnné Partie. Jak uvidíte, příliš mnoho jich tu mít nebudeme. Tyto ženy totiž povětšinou na Osadníky z Katanu čas nemají, a proto se také příliš neobjevují v naší databázi. Nevíte někdo, proč tomu tak je?
table(
Katan$Pohlaví == "žena" &
Katan$Děti != 0 &
!is.na(Katan$Partie))
FALSE TRUE
198 2
Výsledky z příkazu table() můžeme následně jednoduše uložit do nově vzniklé proměnné. U příkazu summary() můžeme výsledek též uložit, na rozdíl od příkazu table() nám nicméně jeho formát neumožní následnou práci s takto vzniklou databází, proto se ve zbytku lekce zaměříme výhradně na table().
Tabulka <- table(
Katan$Pohlaví == "žena" &
Katan$Děti != 0 &
!is.na(Katan$Partie))
FALSE TRUE
198 2
Vyzkoušejme si nyní další variantu příkazu table(). V ní budeme chtít zjistit počty mužů a žen, kteří pracují a kteří nikoliv. Současně tak budeme vytvářet četnostní tabulku s celkově čtyřmi údaji.
Tabulka <- table(
Katan$Práce,
Katan$Pohlaví)
muž žena
nepracuje 57 36
pracuje 85 22
Co se však stane, použijeme-li v tuto chvíli příkaz View(Tabulka)? Uvidíme to samé jako v konzoli?
View(Tabulka)Formát tabulky vypadá jinak než v konzoli, což v tomto případě nemusí být vždy úplně vhodné (ačkoliv ve většině případů bude, viz osmá kapitola Kalkata: Tidyr). Co v takovém případě dělat? Bude nutné využít následující příkaz as.data.frame.matrix().
Tabulka <-
as.data.frame.matrix(Tabulka) muž žena
nepracuje 57 36
pracuje 85 22
Nyní je již vše v pořádku. Přesvědčme se však.
Ačkoliv bude grafům v R vyhrazena více než celá jedna kapitola, již nyní se podíváme, jak vytvořit zcela jednoduchý krabicový graf, ve kterém využijeme výše diskutovaný příkaz as.data.frame.matrix().
Náš úkol zní. V jaké věkové skupině (0 až 17, 18 až 40, 41 až 64, 65 a více) v rámci databáze Katan tvoří kuřáci největší podíl? Graficky znázorni.
Nejdříve musíme vytvořit novou proměnnou s názvem AgeGroup, která rozdělí osadníky a osadnice do čtyř věkových skupin.
AgeGroup <- cut(
Katan$Věk, breaks = c(0, 17, 40, 64, 100),
right = TRUE,
labels = c("0 až 17", "18 až 40", "41 až 64", "65 a více"))[1] 0 až 17 0 až 17 0 až 17 0 až 17 0 až 17 0 až 17
Levels: 0 až 17 18 až 40 41 až 64 65 a více
Poté vytvoříme nový soubor MoreData, který bude obsahovat i nově vytvořenou proměnnou AgeGroup. K tomu využijeme příkaz cbind(), který prozatím ještě neznáte a jež si blíže představíme v přespříští lekci.
MoreData <- cbind(Katan, AgeGroup) Partie Věk Pohlaví Vzdělání Kolej Práce Kouření Klub Děti AgeGroup
1 4 13 žena ZŠ ne nepracuje nekouří nečlen 0 0 až 17
2 4 13 žena ZŠ ne nepracuje nekouří nečlen 0 0 až 17
3 3 14 muž ZŠ ne nepracuje nekouří člen 0 0 až 17
4 8 14 muž ZŠ ne nepracuje nekouří nečlen 0 0 až 17
5 5 15 muž ZŠ ne nepracuje nekouří člen 0 0 až 17
6 6 15 muž ZŠ ne nepracuje nekouří člen 0 0 až 17
Následně stvoříme proměnnou Table, která zobrazí počty kuřáků a nekuřáků v dané věkové kategorii.
Table <- table(MoreData$AgeGroup, MoreData$Kouření)V této chvíli máme data připravena na příkaz as.data.frame.matrix(). Za ním bude následovat kód, pomocí kterého vytvoříme finální datovou tabulku s procenty (FinalData).
Table <- as.data.frame.matrix(Table)FinalData <- cbind(
Table$nekouří/(Table$nekouří + Table$kouří)*100,
Table$kouří/(Table$nekouří + Table$kouří)*100) [,1] [,2]
[1,] 92.30769 7.692308
[2,] 67.54967 32.450331
[3,] 57.89474 42.105263
[4,] 0.00000 100.000000
V této chvíli již máme vytvořenou závěrečnou tabulku, ze které bude vycházet náš sloupcový graf. Před tím nicméně bude nutné tabulku ještě transponovat, jelikož chceme mít vždy jeden sloupec pro danou věkovou kategorii.
FinalData <- t(FinalData) [,1] [,2] [,3] [,4]
[1,] 92.307692 67.54967 57.89474 0
[2,] 7.692308 32.45033 42.10526 100
Na úplný závěr vytvoříme samotný graf.
barplot(FinalData,
# parametr col určuje barvy ve sloupcích, ty udáváme ve formátu HEX
col = c("#323A85","#FFD900"),
# names.arg určí popisky na x-ové ose
names.arg = c("0 až 17 let", "18 až 40 let",
"41 až 64 let", "65 let a více"),
# las = 1 určí horizontální směr popisků na osách
las = 1)A takto vypadá pro rekapitulaci celý skript dohromady.
AgeGroup <- cut(
Katan$Věk, breaks = c(0, 17, 40, 64, 100),
right = TRUE,
labels = c("0 až 17", "18 až 40", "41 až 64", "65 a více"))
MoreData <- cbind(Katan, AgeGroup)
Table <- table(MoreData$AgeGroup, MoreData$Kouření)
Table <- as.data.frame.matrix(Table)
FinalData <- cbind(
Table$nekouří/(Table$nekouří + Table$kouří)*100,
Table$kouří/(Table$nekouří + Table$kouří)*100)
FinalData <- t(FinalData)
barplot(FinalData,
col = c("#323A85","#FFD900"),
names.arg = c("0 až 17 let", "18 až 40 let",
"41 až 64 let", "65 let a více"),
las = 1)Pokračujme dalším příkazem funkce table(). V něm budeme chtít zjistit počty pracujících podle pohlaví, a to vše podle vzdělání. Oproti předchozímu příkazu tudíž vytvoříme četnostní tabulku rozdělenou podle hodnot ze tří proměnných.
Tabulka <- table(
Katan$Práce,
Katan$Pohlaví,
Katan$Vzdělání), , = Bc - VŠ
muž žena
nepracuje 6 4
pracuje 0 9
, , = SŠ
muž žena
nepracuje 31 19
pracuje 39 4
, , = VŠ
muž žena
nepracuje 0 0
pracuje 41 9
, , = ZŠ
muž žena
nepracuje 20 13
pracuje 5 0
Ačkoliv v konzoli vypadá formát souboru Tabulka jako array (pole), přesto zjistíme, že tu stále pracujeme s datovou tabulkou, o čemž svědčí nejenom příkaz class(), ale i View().
Příklad 5
Zjistěte procento kuřáků a nekuřáků v databázi Katan.
Příklad 6
Zjistěte počet žen, které bydlí na koleji a mají děti.
Příklad 7
Zjistěte počet mužů a žen, kteří bydlí na koleji a kteří nikoliv.
Příklad 8
Zjistěte, zdali muži chodí procentuálně více do práce než ženy. Vytvořte přehlednou tabulku, která bude zobrazovat tyto sloupce:
První řádek by měl charakterizovat muže, druhý ženy.
Příklad 9
Vytvořte četnostní tabulku mužů a žen podle jejich vzdělání a kouření.
Příklad 10
Vytvořte v rámci databáze Katan faktorovou proměnnou Rodič, která bude rozdělovat jedince do čtyř skupin podle proměnné Děti na bezdětný, rodič začátečník (jedno dítě), pokročilý rodič (dvě děti) a zasloužilý rodič (tři a více dětí). Následně zjistěte procentuální zastoupení těchto čtyř skupin.
Filtrace dat
Práce s daty obsahuje neustálou potřebu údaje různě třídit a filtrovat. Při tom dochází k tvorbě nejenom nových proměnných, ale i celých databází. Pojďme se proto podívat jak na ně. Začneme tím, že se seznámíme s tvorbu logických vektorů ve tvaru TRUE a FALSE.
Následující skript si klade za cíl vytvořit v konzoli vektor (bez vytvoření proměnné), který bude obsahovat tolik hodnot TRUE a FALSE jako databáze Katan. TRUE nastane pouze v případě, bude-li daný řádek databáze Katan obsahovat ženu od 15 do 20 let (včetně), u níž nechybí hodnota pro proměnnou Partie.
Katan$Pohlaví == "žena" &
Katan$Věk >= 15 &
Katan$Věk <= 20 &
!is.na(Katan$Partie) [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE
[13] TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
[25] TRUE FALSE FALSE FALSE TRUE TRUE FALSE TRUE TRUE FALSE TRUE TRUE
[37] TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE
[49] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[157] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[169] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[193] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
Chceme-li předchozí vektor uložit, není nic jednoduššího než výsledek přiřadit proměnné s novým jménem, v našem případě FemData.
FemData <-
Katan$Pohlaví == "žena" &
Katan$Věk >= 15 &
Katan$Věk <= 20 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE
[13] TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
[25] TRUE FALSE FALSE FALSE TRUE TRUE FALSE TRUE TRUE FALSE TRUE TRUE
[37] TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE
[49] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[157] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[169] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[193] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
Je-li však naším cílem vytvořit novou databázi, která bude obsahovat pouze ty řádky, jež splňují výše uvedené parametry, bude nutné povolat do služby hranaté závorky. V následujícím příkazu si prosím všimněte čárky uvnitř závorky. Vzhledem k tomu, že budeme postupovat v naší selekci po řádcích, a nikoliv po sloupcích, budou podmínky uvedeny hned za závorkou a teprve až po nich bude následovat čárka. V případě, že za čárkou bude následovat konec závorky, znamená to, že v nové databázi FemData budeme chtít zachovat všechny sloupce z databáze Katan.
FemData2<- Katan[
Katan$Pohlaví == "žena" &
Katan$Věk > 15 &
Katan$Věk <= 20, ] # A tibble: 19 x 9
Partie Věk Pohlaví Vzdělání Kolej Práce Kouření Klub Děti
<dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 3 16 žena ZŠ ne nepracuje nekouří člen 0
2 5 16 žena ZŠ ne nepracuje nekouří nečlen 0
3 4 16 žena ZŠ ne nepracuje nekouří člen 0
4 6 17 žena ZŠ ne nepracuje nekouří člen 0
5 7 17 žena ZŠ ne nepracuje nekouří člen 0
6 8 18 žena SŠ ano nepracuje nekouří člen 0
7 8 18 žena ZŠ ne nepracuje nekouří člen 0
8 5 18 žena SŠ ne nepracuje nekouří nečlen 0
9 3 18 žena ZŠ ne nepracuje kouří nečlen 0
10 2 19 žena SŠ ano nepracuje nekouří nečlen 0
11 5 19 žena SŠ ne nepracuje nekouří nečlen 0
12 2 19 žena SŠ ano nepracuje nekouří nečlen 0
13 7 19 žena SŠ ano nepracuje nekouří člen 0
14 6 19 žena SŠ ne nepracuje nekouří člen 0
15 9 19 žena ZŠ ne nepracuje kouří nečlen 0
16 5 20 žena SŠ ano nepracuje nekouří nečlen 0
17 8 20 žena SŠ ano nepracuje nekouří nečlen 0
18 5 20 žena SŠ ne nepracuje kouří člen 0
19 3 20 žena SŠ ano nepracuje kouří člen 0
Pokud bychom nicméně chtěli zachovat pouze první sloupec (proměnnou Partie) a ostatní už nikoliv, vypadal by příkaz následovně.
FemData2<- Katan[
Katan$Pohlaví == "žena" &
Katan$Věk > 15 &
Katan$Věk <= 20, 1] # A tibble: 19 x 1
Partie
<dbl>
1 3
2 5
3 4
4 6
5 7
6 8
7 8
8 5
9 3
10 2
11 5
12 2
13 7
14 6
15 9
16 5
17 8
18 5
19 3
Výše uvedený příkaz by bylo možné napsat ještě jedním způsobem. V něm už čárku uvnitř hranaté závorky nenalezneme, jelikož vybíráme pouze z jedné konkrétní proměnné (jednoho sloupce) a nikoliv z celé databáze.
FemData2 <-
Katan$Partie[
Katan$Pohlaví == "žena" &
Katan$Věk >= 15 &
Katan$Věk <= 20] [1] 3 3 9 3 5 4 6 7 8 8 5 3 2 5 2 7 6 9 5 8 5 3
Filtrovat data samozřejmě nemusíme pouze kvůli tomu, abychom vytvořili novou proměnnou či databázi, ale třeba i za tím účelem, abychom například zjistili věkový průměr dívek, které pracují a mají přitom vysokoškolské vzdělání.
mean(Katan$Věk[
Katan$Pohlaví == "žena" &
Katan$Práce == "pracuje" &
Katan$Vzdělání == "Bc-VŠ" | Katan$Vzdělání == "VŠ"])[1] 31
A co muži? Jaký je jejich věkový průměr ve stejné kategorii?
mean(Katan$Věk[
Katan$Pohlaví == "muž" &
Katan$Práce == "pracuje" &
Katan$Vzdělání == "Bc-VŠ" | Katan$Vzdělání == "VŠ"])[1] 31
Vypadá to možná až neuvěřitelně, ale jejich věkový průměr je naprosto totožný jako u žen.
Třídění dat
Máte rádi, když jsou data v databázi hezky seřazena podle velikosti? Ukažme si nyní, jak lze seřadit naši databázi Katan podle proměnné Partie, následně dle Věku a v závěru podle Pohlaví od nejmenší po největší hodnoty (respektive dle abecedy).
Katan2 <- Katan[order(Katan$Partie, Katan$Věk, Katan$Pohlaví), ]
# pokud chceme od největší po nejmenší, použijeme parametr decreasing = TRUE# A tibble: 200 x 9
Partie Věk Pohlaví Vzdělání Kolej Práce Kouření Klub Děti
<dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 1 23 žena SŠ ano nepracuje nekouří nečlen 1
2 1 24 muž SŠ ne nepracuje kouří člen 0
3 1 24 žena Bc - VŠ ne pracuje nekouří nečlen 0
4 1 24 žena VŠ ne pracuje kouří člen 0
5 1 25 muž VŠ ne pracuje kouří člen 0
6 1 25 žena Bc - VŠ ne pracuje kouří nečlen 0
7 1 27 muž VŠ ne pracuje nekouří člen 1
8 1 28 muž VŠ ne pracuje nekouří nečlen 1
9 1 28 muž VŠ ne pracuje kouří nečlen 0
10 1 28 žena VŠ ne pracuje nekouří nečlen 0
# ... with 190 more rows
Příkaz order() nicméně dokáže mnohem víc. Následující kód nám proto ukáže, kterak lze vytvořit vektor, který bude obsahovat jednotlivá pořadí (nikoliv samotné hodnoty) určité proměnné od nejmenší hodnoty po tu největší. Pro bližší názornost, první číslo ve vektoru Order nabývá hodnoty 90, protože v databázi Katan nalezneme nejnižší hodnotu proměnné Partie právě na 90. místě. V případě, že je stejných hodnot více, dostane přednost vždy ta nejdřívější.
Order <- order(Katan$Partie) [1] 90 92 95 106 108 119 124 126 130 134 136 137 139 140 142 143 144 145
[19] 146 147 149 150 151 152 154 155 157 158 159 161 162 164 165 166 168 174
[37] 175 176 177 178 179 180 181 182 183 185 186 191 193 194 195 196 198 200
[55] 19 24 27 35 37 39 45 48 57 59 64 65 67 71 72 73 79 86
[73] 98 99 100 103 110 114 116 120 121 127 128 129 131 132 133 135 138 141
[91] 171 172 187 189 190 192 197 199 3 8 9 13 33 34 47 50 51 52
[109] 74 80 87 89 93 97 101 102 104 105 111 112 113 115 117 118 122 123
[127] 125 153 156 160 163 167 169 170 173 184 188 1 2 18 23 43 53 56
[145] 60 63 70 75 81 82 88 94 96 107 109 148 5 11 12 14 16 32
[163] 36 44 49 54 58 66 78 83 6 7 17 21 28 41 61 69 84 85
[181] 15 25 26 40 55 62 68 77 91 4 20 29 30 31 38 46 76 10
[199] 22 42
Poslední příkaz, který si tu v této lekci ukážeme, se nazývá sort(). Ten na rozdíl od order() vytvoří vektor se samotnými hodnotami seřazenými od těch nejmenších po největší.
Sort <- sort(Katan$Partie)
# pokud chceme hodnoty v opačném pořadí, použijeme funkci decreasing = TRUE [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[38] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[75] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3
[112] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4
[149] 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7
[186] 7 7 7 7 8 8 8 8 8 8 8 8 9 9 9
Příklad 11
Vytvořte logický vektor, kde TRUE značí muže do 25 let, který odehraje za měsíc alespoň 5 partií deskové hry Osadníci z Katanu.
Příklad 12
Vytvořte novou databázi Katan2, která bude obsahovat pouze ženy do 25 let, které kouří a odehrají alespoň 3 partie deskové hry Osadníci z Katanu. Výslednou databázi seřaďte podle Věku od nejstarší slečny po nejmladší.
V rámci R se budeme nezřídka kdy setkávat s potřebou propojování (a odstraňování) proměnných v data frame. Jak na to se naučíme právě nyní v Buenos Aires. Začneme tím, že si vytvoříme logický vektor, který bude obsahovat TRUE pro muže, kteří chodí do práce. Naším následujícím úkolem bude tento vektor připojit ke stávající databázi Katan. K tomu využijeme příkaz cbind() (c označuje sloupec - column).
MenWork <-
Katan$Pohlaví == "muž" &
Katan$Práce == "pracuje"
MoreData <- cbind(Katan, MenWork) Partie Věk Pohlaví Vzdělání Kolej Práce Kouření Klub Děti MenWork
1 4 13 žena ZŠ ne nepracuje nekouří nečlen 0 FALSE
2 4 13 žena ZŠ ne nepracuje nekouří nečlen 0 FALSE
3 3 14 muž ZŠ ne nepracuje nekouří člen 0 FALSE
4 8 14 muž ZŠ ne nepracuje nekouří nečlen 0 FALSE
5 5 15 muž ZŠ ne nepracuje nekouří člen 0 FALSE
6 6 15 muž ZŠ ne nepracuje nekouří člen 0 FALSE
Výše uvedené dva příkazy (tvorbu vektoru a následné použití příkazu cbind()) lze provést dokonce i dohromady.
MoreData2 <- cbind(
Katan,
MenWork =
Katan$Pohlaví == "muž" &
Katan$Práce == "pracuje")Na druhou stranu zde existuje ještě jeden mnohem triviálnější příkaz než cbind(). Vezměme si do úvahy opět vektor MenWork, který stojí mimo databázi Katan. Pro jeho přidání ke Katanu lze využít i následující styl zápisu.
Katan$MenWork <- MenWorkTakovýto formát velice elegantně přidá vektor MenWork jako další proměnnou databáze Katan (na pozici posledního sloupce).
Kromě příkazu cbind() nesmíme zapomenout ani na paste(). Ten na rozdíl od cbind() spojuje stávající vektory či sloupce data frame přímo do sebe, a vytváří tak zcela nový vektor hodnot.
AgeGender <- paste(
Katan$Věk,
Katan$Pohlaví)[1] "13 žena" "13 žena" "14 muž" "14 muž" "15 muž" "15 muž"
Chceme-li mezi proměnné vložit určitý znak, např. podtržítko, využijeme parametr s názvem sep.
AgeGender <- paste(
Katan$Věk,
Katan$Pohlaví,
sep = "_")[1] "13_žena" "13_žena" "14_muž" "14_muž" "15_muž" "15_muž"
Příkazy paste() a cbind() lze opět zkombinovat v jeden příkaz.
Katan2 <- cbind(
Katan,
AgeGender = paste(
Katan$Věk,
Katan$Pohlaví)) Partie Věk Pohlaví Vzdělání Kolej Práce Kouření Klub Děti AgeGender
1 4 13 žena ZŠ ne nepracuje nekouří nečlen 0 13 žena
2 4 13 žena ZŠ ne nepracuje nekouří nečlen 0 13 žena
3 3 14 muž ZŠ ne nepracuje nekouří člen 0 14 muž
4 8 14 muž ZŠ ne nepracuje nekouří nečlen 0 14 muž
5 5 15 muž ZŠ ne nepracuje nekouří člen 0 15 muž
6 6 15 muž ZŠ ne nepracuje nekouří člen 0 15 muž
Bratrem příkazu cbind() je rbind(), který spojuje databáze po řádcích. Jeho praktické využití může být například v tom, máme-li za cíl připojit ke stávající databázi nové řádky, například nově získaná data od dalších respondentů. Vytvořme si proto novou databázi KatanNEW, která bude obsahovat dvě pozorování pro všech devět proměnných databáze Katan. Tu následně připojíme ke stávající databázi Katan.
KatanNEW <- data.frame(
Partie = c(2, 3),
Věk = c(20, 30),
Pohlaví = c("muž", "muž"),
Vzdělání = c("SŠ", "SŠ"),
Kolej = c("ne", "ne"),
Práce = c("pracuje", "pracuje"),
Děti = c(0, 1),
Kouření = c("nekouří", "nekouří"),
Klub = c("nečlen", "nečlen"))
Katan <- rbind(Katan, KatanNEW)
tail(Katan)# A tibble: 6 x 9
Partie Věk Pohlaví Vzdělání Kolej Práce Kouření Klub Děti
<dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 2 68 muž ZŠ ne pracuje kouří nečlen 4
2 1 69 muž ZŠ ne pracuje kouří nečlen 4
3 2 74 muž ZŠ ne pracuje kouří nečlen 2
4 1 75 muž ZŠ ne pracuje kouří nečlen 2
5 2 20 muž SŠ ne pracuje nekouří nečlen 0
6 3 30 muž SŠ ne pracuje nekouří nečlen 1
Použili jste někdy v Excelu příkaz svyhledat? Představte si, že máte dvě databáze, které chcete vzájemně propojit. První tabulka například obsahuje jméno, příjmení studenta a jeho identifikační číslo UČO. Ta druhá zahrnuje známky z matematiky, dějepisu a též UČO, které je pojítkem obou databází. Vaším cílem je spojit tyto databáze do jedné, jež bude obsahovat celkem pět sloupců (jméno, příjmení, UČO, matematika a dějepis).
data1 <-
data.frame(
UČO = c(39, 45, 50, 60, 70,
89, 40, 65, 44, 77),
jméno = c("Petr", "Ondřej", "Jana", "Eva", "David",
"Alois", "Filip", "Magda", "Bára", "Jakub"),
příjmení = c("Novák", "Dvořák", "Nováková", "Dvořáková", "Svoboda",
"Novotný", "Černý", "Svobodová", "Procházková", "Kučera"))
data2 <-
data.frame(
UČO = c(45, 39, 77, 60, 70,
89, 65, 40, 44, 50),
matematika = c(1, 2, 2, 3, 4,
5, 3, 1, 2, 2),
dějepis = c(2, 1, 2, 4, 1,
5, 1, 1, 3, 1))
MergeData <-
merge(data1, data2[ , c("UČO", "matematika", "dějepis")], by = "UČO") UČO jméno příjmení
1 39 Petr Novák
2 45 Ondřej Dvořák
3 50 Jana Nováková
4 60 Eva Dvořáková
5 70 David Svoboda
6 89 Alois Novotný
7 40 Filip Černý
8 65 Magda Svobodová
9 44 Bára Procházková
10 77 Jakub Kučera
UČO matematika dějepis
1 45 1 2
2 39 2 1
3 77 2 2
4 60 3 4
5 70 4 1
6 89 5 5
7 65 3 1
8 40 1 1
9 44 2 3
10 50 2 1
UČO jméno příjmení matematika dějepis
1 39 Petr Novák 2 1
2 40 Filip Černý 1 1
3 44 Bára Procházková 2 3
4 45 Ondřej Dvořák 1 2
5 50 Jana Nováková 2 1
6 60 Eva Dvořáková 3 4
7 65 Magda Svobodová 3 1
8 70 David Svoboda 4 1
9 77 Jakub Kučera 2 2
10 89 Alois Novotný 5 5
K souboru data1, který obsahuje údaje o jméně, příjmení a UČu, byla přiřazena databáze data2 se sloupci matematika a dějepis. Sloupec UČO znovu přiřazen nebude a zůstane v nové databázi MergeData pouze jednou. Pozor však na to, aby v obou souborech byl název proměnné, vzhledem ke které dojde ke spojení, stejný, a to včetně velikosti písmen.
Přidávat nové proměnné do data frame umíme. Co ale opačný případ? Vzpomenete si na jednu z možností odebrání proměnné, se kterou jsme se seznámili již v předchozí kapitole?
LessData <- Katan[ ,-(6)]# A tibble: 6 x 8
Partie Věk Pohlaví Vzdělání Kolej Kouření Klub Děti
<dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl>
1 4 13 žena ZŠ ne nekouří nečlen 0
2 4 13 žena ZŠ ne nekouří nečlen 0
3 3 14 muž ZŠ ne nekouří člen 0
4 8 14 muž ZŠ ne nekouří nečlen 0
5 5 15 muž ZŠ ne nekouří člen 0
6 6 15 muž ZŠ ne nekouří člen 0
Následující příkaz už ale jistě neznáte. V něm totiž nebudeme využívat pořadí proměnné v databázi, ale jejího názvu.
Katan$Práce <- NULL# A tibble: 6 x 8
Partie Věk Pohlaví Vzdělání Kolej Kouření Klub Děti
<dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl>
1 4 13 žena ZŠ ne nekouří nečlen 0
2 4 13 žena ZŠ ne nekouří nečlen 0
3 3 14 muž ZŠ ne nekouří člen 0
4 8 14 muž ZŠ ne nekouří nečlen 0
5 5 15 muž ZŠ ne nekouří člen 0
6 6 15 muž ZŠ ne nekouří člen 0
Příklad 13
Vytvořte proměnnou s názvem Pohlaví_Vzdělání, která v sobě bude obsahovat údaje z obou těchto proměnných. Tuto proměnnou následně připojte k databázi Katan.
Příklad 14
Výše uvedenou proměnnou Pohlaví_Vzdělání odstraňte z databáze Katan2.
Příklad 15
Vytvořte Databázi A, která obsahuje dvě proměnné. Tou první bude proměnná ID, jež obsahuje čísla od jedné do 30 (náhodně uspořádaná, na příkaz 1:30 tudíž zapomeňte). Tou druhou proměnnou bude zeměpis, která obsahuje náhodný vektor známek z písemky. Následně vytvořte obdobnou Databázi B, která bude naopak obsahovat známky z matematiky. Vaším úkolem bude tyto dvě databáze spojit podle proměnné ID. A aby to nebylo tak jednoduché, známky z jednotlivých předmětů se budou vyskytovat s následující pravděpodobností (1: 30 %; 2: 50 %; 3: 10 %; 4: 5 %; 5: 5 %). Jak je vidět, pan učitel byl velice mírný.
Společnou vlastností příkazů apply() a tapply() je schopnost aplikovat funkci na vybrané části datového souboru bez použití cyklu, což má výhody v přehlednosti i rychlosti výpočtu. Co se však za touto tajuplnou větou skrývá? Odpověď nenalezneme v temných zákoutích Ria, ale v této lekci. Stejně jako v těch předchozích, i nyní bude nejrychlejší si vše ukázat na konkrétních příkladech. Nejdříve si však vytvořme vzorovou matici, kterou použijeme na ukázku příkazu apply(), který se pojí právě s maticemi.
# vzorová matice
matice <- matrix(c(1:9), nrow = 3, byrow = TRUE) [,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 8 9
Naším prvním úkolem bude vypočítat průměry ve všech sloupcích matice s názvem matice.
apply(matice, MARGIN = 2, FUN = mean)
# margin = 1 znamená počítání po řádcích
# příkaz lze zapsat i jako apply(matice, 2, mean)[1] 4 5 6
Nechceme-li počítat průměry ve všech sloupcích, ale třeba pouze v prvních dvou, použijeme staré dobré hranaté závorky.
apply(matice[ ,1:2], MARGIN = 2, FUN = mean) [1] 4 5
I v matici se nám občas může stát, že nám budou chybět některá data. Pro takový případ tu máme připraven parametr na.rm = TRUE, se kterým jsme se již v této kapitole seznámili (viz Statistika 0).
apply(matice, MARGIN = 2, FUN = mean, na.rm = TRUE) [1] 4 5 6
V rodině funkcí apply() nalezneme i další sourozence. Jedná se například o funkce sapply(), vapply(), lapply() či mapply(). My se však seznámíme pouze s tapply(), který na rozdíl od předchozích příkazů bude mít nejpraktičtější využití, jelikož ho využijeme v rámci data frame. Představte si například, že chcete vypočítat průměr u proměnné Věk. Žádný problém. Co když ale následně budete chtít vypočítat průměr zvlášť u mužů a žen? A co když budete chtít zajít ještě dál a vaším cílem bude zjistit věkový průměr nejenom podle pohlaví, ale i podle toho, zdali jedinci chodí do práce či nikoliv? Bude se vám chtít neustále vypisovat nové a nové řádky skriptu pro mean() nebo byste raději napsali jeden jednoduchý příkaz? V případě, že preferujete druhou možnost, je funkce tapply() pro vás jako stvořena. Podívejme se, jak lze výše diskutovaný příklad jednoduše vyřešit. Začneme tím, že vypočítáme věkové průměry podle pohlaví.
tapply(
Katan$Věk,
Katan$Pohlaví,
FUN = mean,
simplify = TRUE,
na.rm = TRUE)
# příkaz simplify zjednoduší formát zobrazení výsledku
# na.rm = TRUE využijeme tehdy, pokud máme v datech chybějící hodnoty muž žena
29.81690 22.31034
Průměrný věk mužů v našem souboru dat je o více než sedm let vyšší než u žen. To je dáno zejména tím, že muži na rozdíl od žen nepřestávají hrát Osadníky z Katanu ani po dosažení 26 let (viz table a summary). Zkusme nyní tento výrok dokázat pomocí tapply(). K tomu budeme potřebovat napsat skript, který nám vypočítá průměrný věk podle pohlaví pro jedince, kteří ještě nedosáhli 26 let.
# Nejdříve vytvoříme vyfiltrovanou databázi Katan25 a poté
# použijeme samotný příkaz tapply().
Katan25 <- Katan[Katan$Věk < 26, ]
tapply(
Katan25$Věk,
Katan25$Pohlaví,
FUN = mean,
simplify = TRUE)
# podmínku lze vtělit i přímo do tapply() (viz další text)
tapply(
Katan$Věk,
list(Katan$Pohlaví,
Katan$Věk < 26),
FUN = mean,
simplify = TRUE) muž žena
20.23810 20.52083
FALSE TRUE
muž 37.4557 20.23810
žena 30.9000 20.52083
Zde naopak vidíme, že ve věkové skupině do 26 let je průměrný věk žen dokonce o několik měsíců vyšší. Předchozí výrok byl tudíž pravdivý.
V případě, že chceme výsledky rozdělit nejenom podle jedné, ale i více proměnných (nyní podle proměnné Pohlaví a Práce), použijeme datovou strukturu list. V rámci takového listu lze využít i podmínek (viz předchozí skript).
tapply(
Katan$Věk,
list(Katan$Pohlaví,
Katan$Práce),
FUN = mean,
simplify = TRUE) nepracuje pracuje
muž 19.80702 36.52941
žena 19.13889 27.50000
Výsledky výše uvedeného příkazu opět potvrzují naše dřívější zjištění. Ženy na rozdíl od mužů nemají na Osadníky z Katanu čas.
Nevlastním bratrem příkazu tapply() je funkce aggregate(). Ta je navržena tak, aby pracovala na více sloupcích s jednou funkcí a vrátila nám data frame s jedním řádkem pro každou kategorii. Zatímco funkce tapply() je navržena tím způsobem, aby fungovala na jediném vektoru s výsledky vrácenými jako matice nebo pole.
Takto bych to též nepochopil (dovolil jsem si použít větu z nejmenované učebnice), proto nezoufejme a podívejme se na následující příkazy. V prvním z nich se podobně jako u tapply() podíváme na to, jaké jsou věkové průměry našich osadníků podle pohlaví, kouření a jejich pracovního nasazení.
aggregate(Katan$Věk,
list(Katan$Pohlaví,
Katan$Kouření,
Katan$Práce),
FUN = mean,
simplify = TRUE,
na.rm = TRUE)
# Příkaz funguje obdobně jako funkce tapply(), pouze vše
# agreguje do přehledné tabulky data frame (na rozdíl
# od tapply()). Výhodné zvlášť v případě, pokud máme v
# příkazu více položek, podle kterých se objekt (Věk)
# třídí (Pohlaví, Kouření, Práce). Group.1 Group.2 Group.3 x
1 muž kouří nepracuje 21.16667
2 žena kouří nepracuje 20.85714
3 muž nekouří nepracuje 19.44444
4 žena nekouří nepracuje 18.72414
5 muž kouří pracuje 39.85714
6 žena kouří pracuje 26.44444
7 muž nekouří pracuje 34.20000
8 žena nekouří pracuje 28.23077
V příkazu aggregate() lze využít podmínek stejně jako u tapply(). Oproti předchozímu skriptu však budeme chtít, aby naše věkové průměry byly roztříděny i podle toho, zdali je náš osadník z databáze Katan hrdým otcem či matkou (a je mu zákonných 18 let!).
aggregate(
Katan$Věk,
list(Katan$Pohlaví,
Katan$Kouření,
Katan$Práce,
Katan$Věk >= 18 &
Katan$Děti >= 1),
FUN = mean,
simplify = TRUE,
na.rm = TRUE) Group.1 Group.2 Group.3 Group.4 x
1 muž kouří nepracuje FALSE 21.16667
2 žena kouří nepracuje FALSE 20.85714
3 muž nekouří nepracuje FALSE 19.44444
4 žena nekouří nepracuje FALSE 18.57143
5 muž kouří pracuje FALSE 26.25000
6 žena kouří pracuje FALSE 25.12500
7 muž nekouří pracuje FALSE 28.28571
8 žena nekouří pracuje FALSE 28.23077
9 žena nekouří nepracuje TRUE 23.00000
10 muž kouří pracuje TRUE 43.88889
11 žena kouří pracuje TRUE 37.00000
12 muž nekouří pracuje TRUE 35.16279
Nejstaršího věkového průměru dosahují pracující muži kuřáci a otcové od rodin, zatímco nejmladší jsou bezdětné nepracující ženy nekuřačky. Pro většinu z nás nejspíš žádné významné překvapení.
Příklad 16
Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání.
Příklad 17
Vypočítejte medián proměnné Věk podle pohlaví a kouření.
Příklad 18
Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání u jedinců, kteří mají alespoň jedno dítě.
Nenašli jste prozatím funkci, kterou jste hledali? Napište si ji sami. Stačí si prostudovat několik následujících odstavců, které tu jsou pro vás připraveny ve Fortaleze, o níž jste nejspíš nikdy neslyšeli, navzdory tomu, že patří mezi sto největších měst na světě.
Pamatujete si ze školy, jak se počítá obsah a obvod kruhu? Určitě, i když nezastírejte, že jste chvíli museli přemýšlet nebo v horším případě googlit. A pokud už jste v tom, podívejte na následující video, v němž možná konečně pochopíte, kde se tu ty vzorečky vlastně vzaly. My však přemýšlení nemáme příliš v oblibě, proto si napíšeme následující skript, který bude po zadání poloměru vše počítat za nás.
kruh <- function(r) {
obvod <- 2*pi*r
obsah <- pi*r^2
return(c("Obvod kruhu" = obvod, "Obsah kruhu" = obsah))
}
kruh(4) Obvod kruhu Obsah kruhu
25.13274 50.26548
Naše funkce se jmenuje zcela stylově kruh. Jelikož se ale jedná o funkci novou, kterou R prozatím nezná, musíme uvést příkaz function() a do závorky jeho parametr, jenž v našem případě bude značit poloměr r. Následuje složená závorka, do které zapíšeme samotné příkazy nové funkce kruh. Tím prvním bude vzoreček pro výpočet obsahu a tím druhým pro výpočet obvodu. Každá funkce musí mít svůj výstup, proto ještě do složené závorky nezapomeneme zapsat příkaz return() podle výše uvedeného vzoru. Závorku uzavřeme a příkaz vyzkoušíme. Funguje. Ale co když nechceme vypočítat obvod a obsah pouze pro jeden údaj poloměru, ale třeba pro celý dlouhý vektor poloměrů? Vyzkoušejme.
x <- 1:4 # vektor poloměrů
kruh(x)Obvod kruhu1 Obvod kruhu2 Obvod kruhu3 Obvod kruhu4 Obsah kruhu1 Obsah kruhu2
6.283185 12.566371 18.849556 25.132741 3.141593 12.566371
Obsah kruhu3 Obsah kruhu4
28.274334 50.265482
Výsledek tu sice máme, výstup nicméně nevypadá příliš reprezentativně. Co s tím? Místo příkazu c() zkusíme do příkazu return(c(Obvod = obvod, Obsah = obsah)) vepsat list či ještě lépe data.frame.
# list
kruh <- function(r) {
obvod <- 2*pi*r
obsah <- pi*r^2
return(list("Obvod kruhu" = obvod, "Obsah kruhu" = obsah))
}
x <- 1:4
kruh(x)
# data.frame
kruh <- function(r) {
obvod <- 2*pi*r
obsah <- pi*r^2
return(data.frame("Obvod kruhu" = obvod, "Obsah kruhu" = obsah))
}
x <- 1:4
kruh(x)[1] "List"
$`Obvod kruhu`
[1] 6.283185 12.566371 18.849556 25.132741
$`Obsah kruhu`
[1] 3.141593 12.566371 28.274334 50.265482
[1] "Data frame"
Obvod.kruhu Obsah.kruhu
1 6.283185 3.141593
2 12.566371 12.566371
3 18.849556 28.274334
4 25.132741 50.265482
Tento výstup vypadá již o poznání lépe. Nezapomeňme ho proto uložit do naší nové proměnné KRUH. A aby bylo vše tak jak má být, doplníme datovou tabulku o sloupec s hodnotami poloměrů a ten přesuneme na první pozici.
KRUH <- kruh(x)
KRUH <- cbind(KRUH, x)
# nyní ještě přejmenujeme proměnnou x na Poloměr
colnames(KRUH)[3] <- "Poloměr"
# a tu přesuneme na první místo v data frame
KRUH <- KRUH[ , c(3, 1, 2)] Poloměr Obvod.kruhu Obsah.kruhu
1 1 6.283185 3.141593
2 2 12.566371 12.566371
3 3 18.849556 28.274334
4 4 25.132741 50.265482
Na závěr se ještě podívejme do pravého horního panelu, kde nám k sekci values a data nově přibyla sekce functions s naší nově vytvořenou funkcí kruh. Z toho nepřímo vyplývá, že naše funkce bude v R fungovat pouze v rámci právě otevřené relace RStudia. Po jejím ukončení funkce z R zmizí. Uložit ji nicméně lze velice jednoduše jako skript.
Příklad 19
Vytáhněte si rukávy, je tu pro vás připraven jeden docela komplikovaný příklad. Vaším úkolem bude vytvořit funkci s názvem mzdová_kalkulačka. Ta po udání hrubé mzdy vypočítá náklady zaměstnance na sociální pojištění, zdravotní pojištění a daň z příjmů fyzických osob.
Následně vytvořte tři náhodné vektory o sto položkách hodnot, které budou obsahovat údaje o hrubé mzdě, počtu dětí a manželce (nebo manželovi), jejíž (jehož) příjem je nižší než 68 000 Kč za rok (1: ano, 0: ne). Poté pomocí funkce mzdová_kalkulačka vypočítejte výše uvedená pojištění a daň z příjmů. Závěrem vytvořte data frame, který bude obsahovat sedm sloupců: hrubá mzda, čistá mzda, počet dětí, manžel(ka), sociální pojištění, zdravotní pojištění a daň z příjmů.
Pozn. sociální pojištění: 6,5 % z hrubé mzdy; zdravotní pojištění: 4,5 % z hrubé mzdy; daň z příjmů: 15 % ze superhrubé mzdy; superhrubá mzda: hrubá mzda * 1,34; daňová sleva na každého poplatníka: 2 070 Kč; daňová sleva na manžela(ku): 2 070 Kč; daňová sleva na dítě: 1. dítě = 1 267 Kč měsíčně, 2. dítě = 1 617 Kč, 3. a každé další dítě = 2 017 Kč.
Pro zjednodušení uvažujte, že sleva na dítě činí 1 500 Kč na všechny děti. Dosud jsme totiž neprobírali podmínku IF, bez jejíž pomoci byste tento problém nemohli vyřešit. Ta se stane předmětem našeho zájmu v příští kapitole.
V příkladu se nezapomeňte vypořádat s tím, že sleva na poplatníka a manželku může snížit daň maximálně na nulu, zatímco slevy na dítě se mohou přetvořit v tzv. daňový bonus, tj. daň může být záporná. Uveďme si příklad. Daň z příjmů byla u jedince, jenž má nárok na slevu na manželku, vypočítána na hodnotu 3 000 Kč. Sleva na poplatníka a manželku činí dohromady 4 140 Kč. Daň však nemůže jít do záporných hodnot, proto bude činit nula. V případě, že ale takový člověk měl například dvě děti, bude mu vypočítán daňový bonus ve výši 2 884 Kč (respektive v našem příkladu 3 000 Kč).
Příklad 1
Vypočítejte průměr proměnné Partie z databáze Katan. Uvažujte případ, že máte v databázi chybějící údaje.
mean(Katan$Partie, na.rm = TRUE)[1] 3.095
Příklad 2
Vypočítejte minimum a maximum proměnné Partie.
range(Katan$Partie)[1] 1 9
Příklad 3
Vypočítejte korelační koeficient mezi proměnnými Věk a Děti.
cor(
Katan$Věk,
Katan$Děti,
use = "complete.obs") [1] 0.7961328
Příklad 4
Vypočítejte body mass index (hmotnost v kg/výška v m umocněná na druhou) pro následující databázi BMI. Výsledný vektor připojte ke stávající databázi BMI.
BMI <- data.frame(
Hmotnost = c(60, 50, 49, 80, 90, 48, 63, 53, 75, 81),
Výška = c(170, 166, 155, 190, 178, 158, 168, 163, 170, 185))bmi <- BMI$Hmotnost/((BMI$Výška/100)^2)
BMI$bmi <- BMI Hmotnost Výška bmi
1 60 170 20.76125
2 50 166 18.14487
3 49 155 20.39542
4 80 190 22.16066
5 90 178 28.40550
6 48 158 19.22769
7 63 168 22.32143
8 53 163 19.94806
9 75 170 25.95156
10 81 185 23.66691
Příklad 5
Zjistěte procento kuřáků a nekuřáků v databázi Katan.
table(Katan$Smoke)/length(Katan$Smoke)
kouří nekouří
0.315 0.685
Příklad 6
Zjistěte počet žen, které bydlí na koleji a mají děti.
table(
Katan$Pohlaví == "žena" &
Katan$Kolej == "ano" &
Katan$Děti != 0)
FALSE TRUE
199 1
Příklad 7
Zjistěte počet mužů a žen, kteří bydlí na koleji a kteří nikoliv.
table(Katan$Pohlaví, Katan$Kolej)
ano ne
muž 18 124
žena 16 42
Příklad 8
Zjistěte, zdali muži chodí procentuálně více do práce než ženy. Vytvořte přehlednou tabulku, která bude zobrazovat tyto sloupce:
První řádek by měl charakterizovat muže, druhý ženy.
TABULKA <- as.data.frame.matrix(table(Katan$Pohlaví, Katan$Práce))
TABULKA$počet <- TABULKA$pracuje + TABULKA$nepracuje
TABULKA$nepracuje_procento <- round((TABULKA$nepracuje/TABULKA$počet)*100)
TABULKA$pracuje_procento <- round((TABULKA$pracuje/TABULKA$počet)*100) nepracuje pracuje počet nepracuje_procento pracuje_procento
muž 57 85 142 40 60
žena 36 22 58 62 38
Příklad 9
Vytvořte četnostní tabulku mužů a žen podle jejich vzdělání a kouření.
TABULKA <- table(
Katan$Pohlaví,
Katan$Vzdělání,
Katan$Kouření), , = kouří
Bc - VŠ SŠ VŠ ZŠ
muž 2 25 13 7
žena 6 3 5 2
, , = nekouří
Bc - VŠ SŠ VŠ ZŠ
muž 4 45 28 18
žena 7 20 4 11
Příklad 10
Vytvořte v rámci databáze Katan faktorovou proměnnou Rodič, která bude rozdělovat jedince do čtyř skupin podle proměnné Děti na bezdětný, rodič začátečník (jedno dítě), pokročilý rodič (dvě děti) a zasloužilý rodič (tři a více dětí). Následně zjistěte procentuální zastoupení těchto čtyř skupin.
Rodič <- cut(
Katan$Děti,
breaks = c(0, 1, 2, 10),
right = FALSE,
labels = c("bezdětný", "rodič začátečník",
"pokročilý rodič", "zasloužilý rodič"))
table(Rodič)/length(Rodič)Rodič
bezdětný rodič začátečník pokročilý rodič zasloužilý rodič
0.64 0.15 0.14 0.07
Příklad 11
Vytvořte logický vektor, kde TRUE značí muže do 25 let (včetně), který odehraje za měsíc alespoň 5 partií deskové hry Osadníci z Katanu.
muži <-
Katan$Pohlaví == "muž" &
Katan$Věk <= 25 &
Katan$Partie >= 5 [1] FALSE FALSE FALSE TRUE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE
[13] FALSE FALSE TRUE TRUE TRUE FALSE FALSE TRUE FALSE TRUE FALSE FALSE
[25] FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
[37] FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[49] FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE TRUE FALSE FALSE
[61] FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
[73] FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE TRUE TRUE
[85] TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
[97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[157] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[169] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[193] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
Příklad 12
Vytvořte novou databázi Katan2, která bude obsahovat pouze ženy do 25 let, které kouří a odehrají alespoň 3 partie deskové hry Osadníci z Katanu. Výslednou databázi seřaďte podle Věku od nejstarší slečny po nejmladší.
Katan2<- Katan[
Katan$Pohlaví == "žena" &
Katan$Věk <= 25 &
Katan$Kouření == "ano" &
Katan$Partie >= 3, ]
Katan2 <- Katan2[order(Katan$Věk, decreasing=TRUE), ]# A tibble: 11 x 9
Partie Věk Pohlaví Vzdělání Kolej Práce Kouření Klub Děti
<dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 3 25 žena VŠ ne pracuje kouří člen 0
2 3 25 žena Bc - VŠ ne pracuje kouří člen 0
3 4 25 žena VŠ ne pracuje kouří člen 0
4 4 25 žena Bc - VŠ ano nepracuje kouří nečlen 0
5 4 24 žena Bc - VŠ ano pracuje kouří nečlen 0
6 4 23 žena Bc - VŠ ano nepracuje kouří nečlen 0
7 7 21 žena SŠ ano nepracuje kouří člen 0
8 5 20 žena SŠ ne nepracuje kouří člen 0
9 3 20 žena SŠ ano nepracuje kouří člen 0
10 9 19 žena ZŠ ne nepracuje kouří nečlen 0
11 3 18 žena ZŠ ne nepracuje kouří nečlen 0
Příklad 13
Vytvořte proměnnou s názvem Pohlaví_Vzdělání, která v sobě bude obsahovat údaje z obou těchto proměnných. Tuto proměnnou následně připojte k databázi Katan.
Pohlaví_Vzdělání <- paste(
Katan$Pohlaví,
Katan$Vzdělání)
Katan$Pohlaví_Vzdělání <- Pohlaví_Vzdělání
Katan[, c(1:6, 10)]# A tibble: 200 x 7
Partie Věk Pohlaví Vzdělání Kolej Práce Pohlaví_Vzdělání
<dbl> <dbl> <chr> <chr> <chr> <chr> <chr>
1 4 13 žena ZŠ ne nepracuje žena ZŠ
2 4 13 žena ZŠ ne nepracuje žena ZŠ
3 3 14 muž ZŠ ne nepracuje muž ZŠ
4 8 14 muž ZŠ ne nepracuje muž ZŠ
5 5 15 muž ZŠ ne nepracuje muž ZŠ
6 6 15 muž ZŠ ne nepracuje muž ZŠ
7 6 15 muž ZŠ ne nepracuje muž ZŠ
8 3 15 žena ZŠ ne nepracuje žena ZŠ
9 3 15 žena ZŠ ne nepracuje žena ZŠ
10 9 15 žena ZŠ ne nepracuje žena ZŠ
# ... with 190 more rows
Příklad 14
Výše uvedenou proměnnou Pohlaví_Vzdělání odstraňte z databáze Katan2.
Katan$Pohlaví_Vzdělání <- NULLPříklad 15
Vytvořte Databázi A, která obsahuje dvě proměnné. Tou první bude proměnná ID, jež obsahuje čísla od jedné do 30 (náhodně uspořádaná, na příkaz 1:30 tudíž zapomeňte). Tou druhou proměnnou bude zeměpis, která obsahuje náhodný vektor známek z písemky. Následně vytvořte obdobnou Databázi B, která bude naopak obsahovat známky z matematiky. Vaším úkolem bude tyto dvě databáze spojit podle proměnné ID. A aby to nebylo tak jednoduché, známky z jednotlivých předmětů se budou vyskytovat s následující pravděpodobností (1: 30 %; 2: 50 %; 3: 10 %; 4: 5 %; 5: 5 %). Jak je vidět, pan učitel byl velice mírný.
Databáze_A <- data.frame(
ID = sample(30, size = 30, replace = FALSE),
Zeměpis = sample(1:5, size = 30, replace = TRUE, prob=c(.30, .50, .10, .5, .5)))
Databáze_B <- data.frame(
ID = sample(30, size = 30, replace = FALSE),
Matematika = sample(1:5, size = 30, replace = TRUE, prob=c(.30, .50, .10, .5, .5)))
MergeData <-
merge(Databáze_A, Databáze_B[ , c("ID", "Zeměpis", "Matematika")], by = "ID") ID Zeměpis Matematika
1 1 2 2
2 2 2 1
3 3 3 2
4 4 2 1
5 5 3 2
6 6 5 2
7 7 2 1
8 8 2 1
9 9 2 1
10 10 2 2
11 11 2 5
12 12 1 2
13 13 3 3
14 14 2 4
15 15 1 2
16 16 5 2
17 17 1 1
18 18 2 4
19 19 3 2
20 20 2 2
21 21 1 1
22 22 1 2
23 23 2 2
24 24 1 1
25 25 5 1
26 26 2 1
27 27 5 2
28 28 3 2
29 29 3 2
30 30 2 2
Příklad 16
Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání.
aggregate(
Katan$Partie,
list(Katan$Pohlaví,
Katan$Vzdělání),
FUN = mean,
simplify = TRUE,
na.rm = TRUE) Group.1 Group.2 x
1 muž Bc - VŠ 3.666667
2 žena Bc - VŠ 2.692308
3 muž SŠ 2.828571
4 žena SŠ 4.260870
5 muž VŠ 1.634146
6 žena VŠ 2.444444
7 muž ZŠ 4.360000
8 žena ZŠ 5.230769
Příklad 17
Vypočítejte medián proměnné Věk podle pohlaví a kouření.
aggregate(
Katan$Věk,
list(Katan$Pohlaví,
Katan$Kouření),
FUN = median,
simplify = TRUE,
na.rm = TRUE) Group.1 Group.2 x
1 muž kouří 30.0
2 žena kouří 24.5
3 muž nekouří 26.0
4 žena nekouří 21.0
Příklad 18
Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání u jedinců, kteří mají alespoň jedno dítě.
aggregate(
Katan$Partie,
list(Katan$Pohlaví,
Katan$Vzdělání,
Katan$Děti >= 1),
FUN = mean,
simplify = TRUE,
na.rm = TRUE)
# nebo
tapply(
Katan$Partie,
list(Katan$Pohlaví,
Katan$Vzdělání,
Katan$Děti >= 1),
mean,
simplify = TRUE) Group.1 Group.2 Group.3 x
1 muž Bc - VŠ FALSE 3.666667
2 žena Bc - VŠ FALSE 2.692308
3 muž SŠ FALSE 4.000000
4 žena SŠ FALSE 4.409091
5 muž VŠ FALSE 1.500000
6 žena VŠ FALSE 2.500000
7 muž ZŠ FALSE 5.100000
8 žena ZŠ FALSE 5.230769
9 muž SŠ TRUE 1.588235
10 žena SŠ TRUE 1.000000
11 muž VŠ TRUE 1.677419
12 žena VŠ TRUE 2.000000
13 muž ZŠ TRUE 1.400000
, , FALSE
Bc - VŠ SŠ VŠ ZŠ
muž 3.666667 4.000000 1.5 5.100000
žena 2.692308 4.409091 2.5 5.230769
, , TRUE
Bc - VŠ SŠ VŠ ZŠ
muž NA 1.588235 1.677419 1.4
žena NA 1.000000 2.000000 NA
Příklad 19
Vytáhněte si rukávy, je tu pro vás připraven jeden docela komplikovaný příklad. Vaším úkolem bude vytvořit funkci s názvem mzdová_kalkulačka. Ta po udání hrubé mzdy vypočítá náklady zaměstnance na sociální pojištění, zdravotní pojištění a daň z příjmů fyzických osob.
Následně vytvořte tři náhodné vektory o sto položkách hodnot, které budou obsahovat údaje o hrubé mzdě, počtu dětí a manželce (nebo manželovi), jejíž (jehož) příjem je nižší než 68 000 Kč za rok (1: ano, 0: ne). Poté pomocí funkce mzdová_kalkulačka vypočítejte výše uvedená pojištění a daň z příjmů. Závěrem vytvořte data frame, který bude obsahovat sedm sloupců: hrubá mzda, čistá mzda, počet dětí, manžel(ka), sociální pojištění, zdravotní pojištění a daň z příjmů.
Pozn. sociální pojištění: 6,5 % z hrubé mzdy; zdravotní pojištění: 4,5 % z hrubé mzdy; daň z příjmů: 15 % ze superhrubé mzdy; superhrubá mzda: hrubá mzda * 1,34; daňová sleva na každého poplatníka: 2 070 Kč; daňová sleva na manžela(ku): 2 070 Kč; daňová sleva na dítě: 1. dítě = 1 267 Kč měsíčně, 2. dítě = 1 617 Kč, 3. a každé další dítě = 2 017 Kč.
Pro zjednodušení uvažujte, že sleva na dítě činí 1 500 Kč na všechny děti. Dosud jsme totiž neprobírali podmínku IF, bez jejíž pomoci byste tento problém nemohli vyřešit. Ta se stane předmětem našeho zájmu v příští kapitole.
V příkladu se nezapomeňte vypořádat s tím, že sleva na poplatníka a manželku může snížit daň maximálně na nulu, zatímco slevy na dítě se mohou přetvořit v tzv. daňový bonus, tj. daň může být záporná. Uveďme si příklad. Daň z příjmů byla u jedince, jenž má nárok na slevu na manželku, vypočítána na hodnotu 3 000 Kč. Sleva na poplatníka a manželku činí dohromady 4 140 Kč. Daň však nemůže jít do záporných hodnot, proto bude činit nula. V případě, že ale takový člověk měl například dvě děti, bude mu vypočítán daňový bonus ve výši 2 884 Kč (respektive v našem příkladu 3 000 Kč).
mzdová_kalkulačka <- function(Hrubá_mzda, Manželka = 0, Děti = 0) {
sociální <- 0.065 * Hrubá_mzda
zdravotní <- 0.045 * Hrubá_mzda
daň <- (0.15 * (Hrubá_mzda * 1.34) - 2070 - (Manželka * 2070))
daň[daň < 0] <- 0
daň <- daň - (Děti * 1500)
cmzda <- Hrubá_mzda - sociální - zdravotní - daň
return(data.frame(Hrubá_mzda,
"Čistá_mzda" = cmzda,
Manželka,
Děti,
"Sociální_pojištění" = sociální,
"Zdravotní_pojištění" = zdravotní,
"Daň_z_příjmu" = daň))
}
Hrubá_mzda <- sample(18000:50000, size = 100, replace = TRUE)
Manželka <- sample(c(0,1), size = 100, replace = TRUE)
Děti <- sample(0:4, size = 100, replace = TRUE)
mzdy <- data.frame(Hrubá_mzda,Manželka,Děti)
Data <- mzdová_kalkulačka(mzdy$Hrubá_mzda, mzdy$Manželka, mzdy$Děti) Hrubá_mzda Čistá_mzda Manželka Děti Sociální_pojištění Zdravotní_pojištění
1 31727 29929.90 0 4 2062.255 1427.715
2 38944 34902.42 0 4 2531.360 1752.480
3 18439 19274.47 0 3 1198.535 829.755
4 35911 34882.68 1 4 2334.215 1615.995
5 24151 23210.04 0 3 1569.815 1086.795
6 40385 31965.26 1 0 2625.025 1817.325
7 23054 20954.21 0 2 1498.510 1037.430
8 45034 38168.43 1 2 2927.210 2026.530
9 41541 30691.75 0 0 2700.165 1869.345
10 18133 19138.37 1 2 1178.645 815.985
11 22610 21218.29 1 1 1469.650 1017.450
12 48715 41634.63 0 4 3166.475 2192.175
13 47689 36997.72 1 0 3099.785 2146.005
14 36935 35588.22 1 4 2400.775 1662.075
15 49748 36346.37 0 0 3233.620 2238.660
16 20545 18285.05 1 0 1335.425 924.525
17 49156 37438.48 0 1 3195.140 2212.020
18 30895 24856.65 0 1 2008.175 1390.275
19 26352 28296.53 1 4 1712.880 1185.840
20 41289 35018.12 0 3 2683.785 1858.005
21 20061 15892.03 0 0 1303.965 902.745
22 48232 39801.85 0 3 3135.080 2170.440
23 48212 41858.07 1 3 3133.780 2169.540
24 22755 24318.19 1 3 1479.075 1023.975
25 34086 29125.25 1 1 2215.590 1533.870
26 45720 39571.08 0 4 2971.800 2057.400
27 44029 35975.98 1 1 2861.885 1981.305
28 41387 33585.64 0 2 2690.155 1862.415
29 24570 27068.73 1 4 1597.050 1105.650
30 49955 41559.00 1 2 3247.075 2247.975
31 24754 20625.51 0 1 1609.010 1113.930
32 44857 39546.47 1 3 2915.705 2018.565
33 20445 19156.60 0 2 1328.925 920.025
34 49231 44060.16 1 4 3200.015 2215.395
35 28368 24615.55 0 2 1843.920 1276.560
36 32138 25713.08 0 1 2088.970 1446.210
37 19629 20094.38 0 3 1275.885 883.305
38 34237 30729.29 1 2 2225.405 1540.665
39 21301 19746.39 0 2 1384.565 958.545
40 43769 37296.84 1 2 2844.985 1969.605
41 38364 31502.80 0 2 2493.660 1726.380
42 47778 34989.04 0 0 3105.570 2150.010
43 45747 39589.68 0 4 2973.555 2058.615
44 47805 37077.65 1 0 3107.325 2151.225
45 45200 39782.80 1 3 2938.000 2034.000
46 43672 36660.01 0 3 2838.680 1965.240
47 30433 27538.34 0 3 1978.145 1369.485
48 36125 28460.12 0 1 2348.125 1625.625
49 34432 27293.65 0 1 2238.080 1549.440
50 23724 20485.84 1 0 1542.060 1067.580
51 41403 36596.67 0 4 2691.195 1863.135
52 47429 37748.58 0 2 3082.885 2134.305
53 36791 33419.00 0 4 2391.415 1655.595
54 37310 32846.59 1 2 2425.150 1678.950
55 48170 36759.13 0 1 3131.050 2167.650
56 24735 22112.41 0 2 1607.775 1113.075
57 21266 20292.27 1 1 1382.290 956.970
58 36708 27361.81 0 0 2386.020 1651.860
59 34183 32192.09 1 3 2221.895 1538.235
60 31274 23617.79 0 0 2032.810 1407.330
61 39342 35746.64 1 3 2557.230 1770.390
62 40280 34322.92 0 3 2618.200 1812.600
63 37631 30997.76 0 2 2446.015 1693.395
64 25486 23199.85 1 1 1656.590 1146.870
65 37820 30197.98 1 0 2458.300 1701.900
66 46641 40205.65 0 4 3031.665 2098.845
67 20493 22738.77 1 3 1332.045 922.185
68 30672 29203.01 0 4 1993.680 1380.240
69 23076 23039.36 1 2 1499.940 1038.420
70 32180 28742.02 0 3 2091.700 1448.100
71 40018 34712.40 1 2 2601.170 1800.810
72 43595 36606.95 0 3 2833.675 1961.775
73 47280 39145.92 0 3 3073.200 2127.600
74 38955 32480.00 1 1 2532.075 1752.975
75 28698 25412.92 1 1 1865.370 1291.410
76 25102 21435.28 1 0 1631.630 1129.590
77 45669 38035.94 0 3 2968.485 2055.105
78 44397 37159.53 0 3 2885.805 1997.865
79 20916 23051.12 1 3 1359.540 941.220
80 19415 19946.94 0 3 1261.975 873.675
81 29911 25678.68 0 2 1944.215 1345.995
82 41423 36610.45 0 4 2692.495 1864.035
83 25667 24824.56 1 2 1668.355 1155.015
84 29322 23772.86 0 1 1905.930 1319.490
85 45028 41164.29 1 4 2926.820 2026.260
86 47795 39500.75 0 3 3106.675 2150.775
87 42088 35568.63 0 3 2735.720 1893.960
88 22372 18984.31 0 1 1454.180 1006.740
89 31269 29614.34 0 4 2032.485 1407.105
90 40451 36510.74 1 3 2629.315 1820.295
91 18280 17769.20 1 1 1188.200 822.600
92 40056 29668.58 0 0 2603.640 1802.520
93 46119 38345.99 0 3 2997.735 2075.355
94 27903 27295.17 0 4 1813.695 1255.635
95 41623 33748.25 0 2 2705.495 1873.035
96 25520 22653.28 0 2 1658.800 1148.400
97 38591 34659.20 0 4 2508.415 1736.595
98 44692 32862.79 0 0 2904.980 2011.140
99 31648 28945.47 1 2 2057.120 1424.160
100 31434 31798.03 1 4 2043.210 1414.530
Daň_z_příjmu
1 -1692.873
2 -242.256
3 -2863.761
4 -2921.889
5 -1715.649
6 3977.385
7 -436.146
8 1911.834
9 6279.741
10 -3000.000
11 -1095.390
12 1721.715
13 5445.489
14 -2716.065
15 7929.348
16 0.000
17 6310.356
18 2639.895
19 -4843.248
20 1729.089
21 1962.261
22 3124.632
23 1050.612
24 -4066.245
25 1211.286
26 1119.720
27 3209.829
28 3248.787
29 -5201.430
30 2900.955
31 1405.554
32 376.257
33 -960.555
34 -244.569
35 631.968
36 2889.738
37 -2624.571
38 -258.363
39 -788.499
40 1657.569
41 2641.164
42 7533.378
43 1125.147
44 5468.805
45 445.200
46 2208.072
47 -452.967
48 3691.125
49 3350.832
50 628.524
51 252.003
52 4463.229
53 -675.009
54 359.310
55 6112.170
56 -98.265
57 -1365.534
58 5308.308
59 -1769.217
60 4216.074
61 -732.258
62 1526.280
63 2493.831
64 -517.314
65 3461.820
66 1304.841
67 -4500.000
68 -1904.928
69 -2501.724
70 -101.820
71 903.618
72 2192.595
73 2933.280
74 2189.955
75 128.298
76 905.502
77 2609.469
78 2353.797
79 -4435.884
80 -2667.585
81 942.111
82 256.023
83 -1980.933
84 2323.722
85 -1089.372
86 3036.795
87 1889.688
88 926.772
89 -1784.931
90 -509.349
91 -1500.000
92 5981.256
93 2699.919
94 -2461.497
95 3296.223
96 59.520
97 -313.209
98 6913.092
99 -778.752
100 -3821.766